(module woof-machine-utils mzscheme
  (require (only (lib "swindle.ss" "swindle")
                 push! pop! rest)) ;provides oo stuff
  (require (only (lib "misc.ss" "swindle")
                 list-set!)) ;misc helpers
  (require (lib "list.ss" "srfi" "1")) ;pre-prefixed with s:
  (require (lib "34.ss" "srfi")) ;provides exception handling
  (require (all-except (lib "43.ss" "srfi")
                       vector->list
                       vector-fill!))
  (require (lib "defmacro.ss"))
  (require (lib "kw.ss"))
  (require (planet "test.ss" ("schematics" "schemeunit.plt" 2 1)))
  (require (planet "text-ui.ss" ("schematics" "schemeunit.plt" 2)))
  (require (planet "read.ss" ("ryanc" "scripting.plt" 1))) ;provides read-all
  (require "woof-kernel.scm")
  (require (lib "file.ss"))
  (require (lib "port.ss"))
  (require (lib "process.ss"))


    
  (define-struct return-addr (pc fn-code env))
  (define new-return-addr
    (lambda/kw (#:key [pc 0] [fn-code ()] [env ()])
               (make-return-addr
                pc
                fn-code
                env)))
  
  (define-struct machine-state (pc fn-code env stack globals))
  (define new-machine-state
    (lambda/kw (#:key [pc 0] [fn-code ()] [env '(())] [stack ()] [globals (new-woof-globals)])
               (make-machine-state
                pc
                fn-code
                env
                stack
                globals
                )))
  
  (define top-of-stack
    (lambda (state)
      (first (machine-state-stack state))))
  
  (define top-n-of-stack
    (lambda (n state)
      (take (machine-state-stack state) n)))
  
  (define push-stack!
    (lambda (val state)
      (set-machine-state-stack! state
                                (cons val (machine-state-stack state)))))
  
  (define pop-stack!
    (lambda (state)
      (let ((val (first (machine-state-stack state))))
        (set-machine-state-stack! state
                                  (cdr (machine-state-stack state)))
        val)))
  
  (define pop-env!
    (lambda (state)
      (let ((val (first (machine-state-env state))))
        (set-machine-state-env! state
                                (cdr (machine-state-env state)))
        val)))
  
  (define inc-pc!
    (lambda (state)
      (set-machine-state-pc! state (+ 1 (machine-state-pc state)))))
  
  (define current-instr
    (lambda (state)
      (instr-at (machine-state-fn-code state)
                (machine-state-pc state))))
  
  (define arg1
    (lambda (instr)
      (second instr)))
  
  (define arg2
    (lambda (instr)
      (third instr)))
  
  (define instr-at
    (lambda (code i)
      (with-handlers ([exn:fail?
                       (lambda (e) '(END-OF-CODE))])
        (list-ref code i))))
  
  (define env-set-var!
    (lambda (env i j obj)
      (if (>= j (vector-length (list-ref env i)))
          (list-set! env i (vector-copy (list-ref env i) 0 (+ j 5) 0)))
      (vector-set! (list-ref env i) j obj)))
  
  (define env-get-var
    (lambda (env i j)
      (vector-ref (list-ref env i) j)))

   (provide (all-defined)) 
)